#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <wchar.h>
#include <time.h>

#include "../src/rxpoly.h"

// #define CHECK( arg ) check( arg, __LINE__ )

int main()
{
	wchar_t *act;

	wprintf( L"Test for zero-length string match...\t" );
	assert( ! wcscmp( L"a",
				substitute( L"", L".*", L"a", RF_BASIC, RCO_DEFAULT ) ) );
	wprintf( L"\tOK\n" );

	wprintf( L"Tests for literal regexp...\t" );

	assert( ! wcscmp( L"a",
				substitute( L"a", L"b", L"c", RF_BASIC, RCO_DEFAULT ) ) );
	assert( ! wcscmp( L"a",
				substitute( L"a", L".", L"a", RF_BASIC, RCO_DEFAULT ) ) );

// 	assert( matches( L"a", L"a", RF_BASIC ) );
// 	assert( matches( L"a", L"a", RF_EXTENDED ) );
// 	assert( ! matches( L"a", L"A", RF_EXTENDED ) );
// 	assert( matches( L"a", L"A", RF_EXTENDED | RF_ICASE ) );
// 	assert( matches( L"a", L"(a)", RF_EXTENDED ) );
// 	assert( ! matches( L"a", L"(a)", RF_BASIC ) );
// 	assert( matches( L"(a)", L"(a)", RF_BASIC ) );
// 	assert( matches( L"a", L"\\(a\\)", RF_BASIC ) );
// 	assert( matches( L"a", L"(((((a)))))", RF_EXTENDED ) );
	
	assert( ! wcscmp( L"a",
				substitute( L"a", L"(((((A)))))", L"b", RF_EXTENDED, RCO_DEFAULT ) ) );
	assert( ! wcscmp( L"b",
				substitute( L"a", L"(((((A)))))", L"b", RF_EXTENDED | RF_ICASE, RCO_DEFAULT ) ) );
	
// 	assert( matches( L"ab", L"ab", RF_EXTENDED ) );
// 	assert( matches( L"ab", L"a(b)", RF_EXTENDED ) );
	
	act = substitute( L"abab", L"a[^a]", L"c", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( act, L"cc" ) );
	free( act );

	assert( ! wcscmp( L"cc",
				substitute( L"abac", L"a[^a]", L"c", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT ) ) );
	assert( ! wcscmp( L"Abc",
				substitute( L"Abac", L"a[^a]", L"c", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT ) ) );
	
// 	assert( matches( L"ab", L"a[^a]", RF_BASIC | RF_ICASE ) );
// 	assert( ! matches( L"aA", L"a[^a]", RF_BASIC | RF_ICASE ) );
// 	assert( matches( L"abcdef", L"a(b)c((d).)f", RF_EXTENDED ) );
// 	assert( ! matches( L"abCdef ", L"a(b)c((d).)f", RF_EXTENDED ) );
// 	assert( matches( L"ba", L"a", RF_EXTENDED ) );
// 	assert( ! matches( L"baobabaababa", L"bababa", RF_EXTENDED ) );
// 	assert( matches( L"baobabaababa", L"aababa", RF_EXTENDED ) );
// 	assert( matches( L"ab", L"(a)(b)", RF_EXTENDED ) );
// 	assert( matches( L"baobabaababa", L"a(((a)(ba))ba)", RF_EXTENDED ) );
// 	assert( matches( L"abcdefghikjlmnop", L"................", RF_EXTENDED ) );
// 	assert( ! matches( L"abcdefghikjlmnop", L".................", RF_EXTENDED ) );

	wprintf( L"\tOK\n" );


	wprintf( L"Tests for non-nested repetitions...\t" );

	assert( ! wcscmp( L"cbcc",
				substitute( L"baa", L"a*", L"c", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT ) ) );

	assert( ! wcscmp( L"bc",
				substitute( L"baa", L"a+", L"c", RF_EXTENDED, RCO_DEFAULT ) ) );

// 	assert( matches( L"", L"a*", RF_EXTENDED ) );
// 	assert( matches( L"b", L"a*", RF_EXTENDED ) );
// 
// 	assert( matches( L"baa", L"aa*", RF_EXTENDED ) );
// 	assert( ! matches( L"", L"aa*", RF_EXTENDED ) );
// 	assert( ! matches( L"b", L"aa*", RF_EXTENDED ) );
// 
// 	assert( matches( L"baa", L"(aa){1,}", RF_EXTENDED ) );
// 	assert( ! matches( L"", L"(aa){1,}", RF_EXTENDED ) );
// 	assert( ! matches( L"b", L"(aa){1,}", RF_EXTENDED ) );
// 
// 	assert( matches( L"baa", L"(aa|b){2,2}", RF_EXTENDED ) );
// 	assert( ! matches( L"baba", L"(aa|b){2,2}", RF_EXTENDED ) );
// 	assert( matches( L"baaba", L"(aa|b){2,2}", RF_EXTENDED ) );
// 	assert( matches( L"baaba", L"(a(a)|b){2,2}", RF_EXTENDED ) );
// 	assert( matches( L"baaba", L"b(a(a)|b){2,2}", RF_EXTENDED ) );
// 	assert( ! matches( L"baaa", L"b(a(a)|b){2,2}", RF_EXTENDED ) );
// 
// 	assert( matches( L"", L"(a*(b*))c*(d*(e*)*)", RF_EXTENDED ) );
// 	assert( ! matches( L"", L"(a*(b*))xc*(d*(e*)*)", RF_EXTENDED ) );
// 	assert( matches( L"x", L"xc*d*", RF_EXTENDED ) );
// 	assert( matches( L"x", L"xc*(d*(e*)*)", RF_EXTENDED ) );

	assert( ! wcscmp( L"",
					substitute( L"abc", L"(a*(b*))c*(d*(e*)*)", L"", RF_EXTENDED, RCO_DEFAULT ) ) );

	assert( ! wcscmp( L"abc",
					substitute( L"abc", L"(a*(b*))xc*(d*(e*)*)", L"y", RF_EXTENDED, RCO_DEFAULT ) ) );

	assert( ! wcscmp( L"ydaey",
					substitute( L"abxcccedaexd", L"(a*(b*))xc*(d*(e*)*)", L"y", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT ) ) );

	assert( ! wcscmp( L"yaey",
					substitute( L"abxcccedaexd", L"(a*(b*))xc*(d*(e*))*", L"y", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT ) ) );

// 
// 	assert( matches( L"bacabacababaabca", L"((((a(a)|b){2,2})))", RF_EXTENDED ) );
// 	assert( ! matches( L"bacabacababaabca", L"((((a(a)|b){4,})))", RF_EXTENDED ) );
// 
// 	assert( matches( L"abbc", L"ab{1,2}c", RF_EXTENDED ) );
// 	assert( ! matches( L"abbbc", L"ab{1,2}c", RF_EXTENDED ) );
// 
// 	assert( matches( L"ab", L"a{1}b{1}", RF_EXTENDED ) );
// 	assert( matches( L"baba", L"a{1,2}a*b{1}", RF_EXTENDED ) );
// 	assert( matches( L"abcca", L"bc{2,2}", RF_EXTENDED ) );
// 	assert( matches( L"XXXaabcccdXXaabcccddX", L"a{2}bc{3}d{1,2}d", RF_EXTENDED ) );
// 	assert( ! matches( L"XXXaabcccdXXaabcccdX", L"a{2}bc{3}d{1,2}d", RF_EXTENDED ) );
// 
// 	assert( matches( L"abbcccd", L"ab{1,2}c{0,3}d", RF_EXTENDED ) );
// 	assert( ! matches( L"abbbccccd", L"ab{1,2}c{0,3}d", RF_EXTENDED ) );

	wprintf( L"\tOK\n" );

// 
// 	wprintf( L"Tests for nested repetitions...\t" );
// 
// 	assert( matches( L"aa", L"(a{1}){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"abcabcd", L"(a{1,2}bc){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"abcbcd", L"(a*bc){2,4}", RF_EXTENDED ) );
// 	assert( ! matches( L"abcbad", L"(a*bc){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"bbc", L"(bc*){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"bccbc", L"(bc*){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"abcaccbc", L"(b(a|c)*){2,4}", RF_EXTENDED ) );
// 	assert( ! matches( L"abcdccbc", L"(b(a|c)*){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"acbbcd", L"(bc*){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"baabcd", L"(a*b){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"aabbcd", L"(a*b){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"abcaaabcd", L"(a*bc){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"abcaaabcd", L"(aa?a?bc){2,4}", RF_EXTENDED ) );
// 	assert( ! matches( L"abcabaabcd", L"(a*bc){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"bb", L"(a*b){1,2}(a*b){1,2}", RF_EXTENDED ) );
// 	assert( matches( L"bbbb", L"(a*b){2,4}(a*b){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"babbab", L"(a*b){2,4}(a*b){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"efgdaddabcaaabcd", L"g(d(a|d)){1,2}", RF_EXTENDED ) );
// 	assert( matches( L"efgdaddabcaaabcd", L"g(d(a|d)){1,2}(a*bc){2,4}", RF_EXTENDED ) );
// 	assert( matches( L"efgdaddaabcaaabcd", L"g(d(a|d)){1,2}(aaa*bc){2,4}", RF_EXTENDED ) );
// 	assert( ! matches( L"efgdadaddabcaaabcd", L"g(d(a|d)){1,2}(a*bc){2,4}", RF_EXTENDED ) );
// 
// 	wprintf( L"\tOK\n" );
// 

	wprintf( L"Tests for anchors...\t" );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\<.", L"w", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\twhoj_wvete-w$wby ", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\<.\\>", L"w", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\tahoj_svete-w$aby ", act ) );
	free( act );

	act = substitute( L"a_b", L"\\b.", L"w", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"www", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\b.", L"w", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\twhojwwvetewwwwbyw", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\b.*\\b", L"w", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\tww ", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\b\\w+\\b", L"word", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\tword_word-word$word ", act ) );
	free( act );

// 	assert( matches( L"a", L"^a$", RF_EXTENDED ) );
// 	assert( matches( L"", L"^$", RF_EXTENDED ) );
// 	assert( ! matches( L"ba", L"^a", RF_EXTENDED ) );
// 	assert( ! matches( L"ba", L"b$a", RF_EXTENDED ) );
// 	assert( ! matches( L"ba", L"b^a", RF_EXTENDED ) );
// 
// 	assert( matches( L"ba", L"a$$$", RF_EXTENDED ) );
// 	assert( ! matches( L"ba", L"^$^ba$$$", RF_EXTENDED ) );
// 	assert( matches( L"", L"^$^$$$", RF_EXTENDED ) );
// 
// 	assert( matches( L"aab", L"(aa|b)$", RF_EXTENDED ) );
// 	assert( matches( L"aab", L"(aaa|b$)", RF_EXTENDED ) );
// 	assert( ! matches( L"aab", L"(aa$|^b)", RF_EXTENDED ) );
// 	assert( matches( L"aab", L"(a?^a|$b)", RF_EXTENDED ) );
// 	assert( matches( L"aab", L"(a?^aa?|b$){1,2}", RF_EXTENDED ) );

	wprintf( L"\tOK\n" );

	wprintf( L"Tests for references in the substitute expression...\t" );

	act = substitute( L"a", L".", L"\\0", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"a", act ) );
	free( act );

	act = substitute( L"abc", L".", L"\\0", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"abc", act ) );
	free( act );

	act = substitute( L"abc", L".", L"\\0\\0", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"aabbcc", act ) );
	free( act );

	act = substitute( L"abc", L"(a|c)", L"\\0\\0", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"aabcc", act ) );
	free( act );

	act = substitute( L"abc", L".", L"", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"", act ) );
	free( act );

	act = substitute( L"a", L"(.)", L"\\1", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"a", act ) );
	free( act );

	act = substitute( L"ab", L"(.)(.)", L"\\1\\2\\2\\1", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"abba", act ) );
	free( act );

	act = substitute( L"xabac", L"((.)([^a]))", L"\\2\\3\\3\\2\\", RF_EXTENDED, RCO_DEFAULT );
	assert( ! wcscmp( L"xabba\\ac", act ) );
	free( act );

	act = substitute( L"ab", L"((.)(.))", L"\\2\\3\\3\\2\\", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"abba\\", act ) );
	free( act );

	act = substitute( L"ab", L"((.)(.))", L"\\2\\3\\3\\2\\\\1", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"abba\\1", act ) );
	free( act );

	act = substitute( L"ab", L"((.)(.))", L"\\2\\3\\3\\2\\\\\\1", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"abba\\ab", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\b\\w+\\b", L"word(\\1)", RF_EXTENDED, RCO_DEFAULT );
	assert( ! wcscmp( L"\tword(\\1)_svete-4$aby ", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"\\b\\w+\\b", L"word(\\1)", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\tword(\\1)_word(\\1)-word(\\1)$word(\\1) ", act ) );
	free( act );

	act = substitute( L"\tahoj_svete-4$aby ", L"(\\b\\w+)\\b", L"word(\\1)", RF_EXTENDED | RF_GLOBAL, RCO_DEFAULT );
	assert( ! wcscmp( L"\tword(ahoj)_word(svete)-word(4)$word(aby) ", act ) );
	free( act );

	wprintf( L"\tOK\n" );

	wprintf( L"Tests for substitute finished.\n" );
	return 0;
}

// int check( int errno, int line )
// {
// 	if( errno != 0 )
// 		fprintf( stderr, "Error \"%d\" in line number %d.\n", strerror( -errno ), line );
// }
